package com.zzu.base.scheduler;

import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import jakarta.annotation.Resource;
import java.util.*;

/**
 * Quartz任务管理器，封装任务的增删改查操作
 */
@Component
public class QuartzJobManager {

    private static final Logger log = LoggerFactory.getLogger(QuartzJobManager.class);

    @Resource
    private Scheduler scheduler;

    // ========================== 新增任务 ==========================

    /**
     * 添加Cron表达式任务（重复执行）
     * @param jobClass 任务实现类
     * @param jobName 任务名称
     * @param jobGroup 任务组
     * @param cronExpression Cron表达式
     * @param dataMap 任务参数
     */
    public void addCronJob(Class<? extends Job> jobClass,
                           String jobName,
                           String jobGroup,
                           String cronExpression,
                           JobDataMap dataMap) throws SchedulerException {
        // 1. 构建任务标识
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup);

        // 2. 检查任务是否已存在
        if (scheduler.checkExists(jobKey)) {
            throw new SchedulerException("Cron任务已存在：" + jobGroup + ":" + jobName);
        }

        // 3. 创建任务详情
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobKey)
                .setJobData(dataMap)
                .storeDurably()
                .build();

        // 4. 创建Cron触发器
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .forJob(jobDetail)
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .build();

        // 5. 注册任务和触发器
        scheduler.scheduleJob(jobDetail, trigger);
        log.info("Cron任务添加成功：{}:{}，表达式：{}", jobGroup, jobName, cronExpression);
    }

    /**
     * 添加一次性任务（仅执行一次）
     * @param jobClass 任务实现类
     * @param jobName 任务名称
     * @param jobGroup 任务组
     * @param executeTime 执行时间（未来时间）
     * @param dataMap 任务参数
     */
    public void addOneTimeJob(Class<? extends Job> jobClass,
                              String jobName,
                              String jobGroup,
                              Date executeTime,
                              JobDataMap dataMap) throws SchedulerException {
        // 1. 校验时间有效性
        if (executeTime.before(new Date())) {
            throw new SchedulerException("执行时间必须晚于当前时间");
        }

        // 2. 构建任务标识
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup);

        // 3. 检查任务是否已存在
        if (scheduler.checkExists(jobKey)) {
            throw new SchedulerException("一次性任务已存在：" + jobGroup + ":" + jobName);
        }

        // 4. 创建任务详情
        JobDetail jobDetail = JobBuilder.newJob(jobClass)
                .withIdentity(jobKey)
                .setJobData(dataMap)
                .storeDurably()
                .build();

        // 5. 创建Simple触发器（执行一次）
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .forJob(jobDetail)
                .startAt(executeTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withRepeatCount(0)) // 重复次数：0（仅执行一次）
                .build();

        // 6. 注册任务和触发器
        scheduler.scheduleJob(jobDetail, trigger);
        log.info("一次性任务添加成功：{}:{}，执行时间：{}", jobGroup, jobName, executeTime);
    }

    // ========================== 删除任务 ==========================

    /**
     * 删除任务（同时删除关联的触发器）
     * @param jobName 任务名称
     * @param jobGroup 任务组
     */
    public void deleteJob(String jobName, String jobGroup) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        // 删除任务（会自动删除关联的触发器）
        boolean result = scheduler.deleteJob(jobKey);
        if (result) {
            log.info("任务删除成功：{}:{}", jobGroup, jobName);
        } else {
            log.warn("任务删除失败（任务不存在）：{}:{}", jobGroup, jobName);
        }
    }

    // ========================== 暂停/恢复任务 ==========================

    /**
     * 暂停任务
     * @param jobName 任务名称
     * @param jobGroup 任务组
     */
    public void pauseJob(String jobName, String jobGroup) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        scheduler.pauseJob(jobKey);
        log.info("任务已暂停：{}:{}", jobGroup, jobName);
    }

    /**
     * 恢复任务
     * @param jobName 任务名称
     * @param jobGroup 任务组
     */
    public void resumeJob(String jobName, String jobGroup) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        scheduler.resumeJob(jobKey);
        log.info("任务已恢复：{}:{}", jobGroup, jobName);
    }

    // ========================== 更新任务 ==========================

    /**
     * 更新Cron任务的执行表达式
     * @param jobName 任务名称
     * @param jobGroup 任务组
     * @param newCronExpression 新的Cron表达式
     */
    public void updateJobCron(String jobName, String jobGroup, String newCronExpression) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup);
        CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);

        if (oldTrigger == null) {
            throw new SchedulerException("触发器不存在：" + triggerKey);
        }

        // 若表达式未变，则不更新
        if (oldTrigger.getCronExpression().equals(newCronExpression)) {
            log.info("Cron表达式未变化，无需更新：{}:{}", jobGroup, jobName);
            return;
        }

        // 构建新触发器
        CronTrigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .forJob(JobKey.jobKey(jobName, jobGroup))
                .withSchedule(CronScheduleBuilder.cronSchedule(newCronExpression))
                .build();

        // 替换触发器
        scheduler.rescheduleJob(triggerKey, newTrigger);
        log.info("任务Cron表达式更新成功：{}:{}，新表达式：{}", jobGroup, jobName, newCronExpression);
    }

    /**
     * 更新一次性任务的执行时间
     * @param jobName 任务名称
     * @param jobGroup 任务组
     * @param newExecuteTime 新的执行时间（未来时间）
     */
    public void updateOneTimeJobTime(String jobName, String jobGroup, Date newExecuteTime) throws SchedulerException {
        // 校验时间有效性
        if (newExecuteTime.before(new Date())) {
            throw new SchedulerException("执行时间必须晚于当前时间");
        }

        TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup);
        SimpleTrigger oldTrigger = (SimpleTrigger) scheduler.getTrigger(triggerKey);

        if (oldTrigger == null) {
            throw new SchedulerException("触发器不存在：" + triggerKey);
        }

        // 构建新触发器
        SimpleTrigger newTrigger = TriggerBuilder.newTrigger()
                .withIdentity(triggerKey)
                .forJob(JobKey.jobKey(jobName, jobGroup))
                .startAt(newExecuteTime)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withRepeatCount(0))
                .build();

        // 替换触发器
        scheduler.rescheduleJob(triggerKey, newTrigger);
        log.info("一次性任务时间更新成功：{}:{}，新时间：{}", jobGroup, jobName, newExecuteTime);
    }

    // ========================== 查询任务 ==========================

    /**
     * 查询任务详情
     * @param jobName 任务名称
     * @param jobGroup 任务组
     * @return 任务详情
     */
    public JobDetail getJobDetail(String jobName, String jobGroup) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        return scheduler.getJobDetail(jobKey);
    }

    /**
     * 查询任务状态
     * @param jobName 任务名称
     * @param jobGroup 任务组
     * @return 状态（NONE/normal/paused/completed/error/blocked）
     */
    public Trigger.TriggerState getJobState(String jobName, String jobGroup) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup);
        return scheduler.getTriggerState(triggerKey);
    }

    /**
     * 查询所有任务
     * @return 任务列表（包含名称、组、状态、表达式等信息）
     */
    public List<Map<String, Object>> getAllJobs() throws SchedulerException {
        List<Map<String, Object>> jobList = new ArrayList<>();

        // 获取所有任务组
        for (String groupName : scheduler.getJobGroupNames()) {
            // 匹配该组下的所有任务
            GroupMatcher<JobKey> matcher = GroupMatcher.jobGroupEquals(groupName);
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);

            for (JobKey jobKey : jobKeys) {
                // 获取任务详情
                JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                // 获取关联的触发器
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);

                for (Trigger trigger : triggers) {
                    Map<String, Object> jobInfo = new HashMap<>();
                    jobInfo.put("jobName", jobKey.getName());
                    jobInfo.put("jobGroup", jobKey.getGroup());
                    jobInfo.put("jobDescription", jobDetail.getDescription());
                    jobInfo.put("triggerName", trigger.getKey().getName());
                    jobInfo.put("triggerGroup", trigger.getKey().getGroup());
                    jobInfo.put("state", scheduler.getTriggerState(trigger.getKey()).name());

                    // 区分Cron和Simple触发器
                    if (trigger instanceof CronTrigger cronTrigger) {
                        jobInfo.put("type", "CRON");
                        jobInfo.put("expression", cronTrigger.getCronExpression());
                    } else if (trigger instanceof SimpleTrigger simpleTrigger) {
                        jobInfo.put("type", "ONE_TIME");
                        jobInfo.put("executeTime", simpleTrigger.getStartTime());
                    }

                    jobList.add(jobInfo);
                }
            }
        }

        return jobList;
    }
}